using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using DSEngine.Sprite;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using DSEngine.Core;
using DSEngine.Sound;
using Microsoft.Xna.Framework.Input.Touch;

namespace DSEngine.Stage
{
    public class Layout : SpObject
    {
        public bool Freeze { get; set; }
        public Color Color { get; set; }
        public Screen Screen { get; set; }
        private List<SpObject> objs = new List<SpObject>();
        private List<SpObject> obj2remove = new List<SpObject>();
        public ResourceManager Content { get; internal set; }
        public SpriteBatch SpriteBatch { get; internal set; }
        public SpriteSortMode SpriteSortMode { get; set; }
        public BlendState BlendState { get; set; }
        public SoundManager SoundPlayer { get;internal set; }
        protected Matrix transform { get; set; }
        public SamplerState SamplerState { get; set; }
        public DepthStencilState DepthStencilState { get; set; }
        public RasterizerState RasterizerState { get; set; }
        Effect effect;
        public Layout(Screen screen)
            :base()
        {
            this.Screen = screen;
            InitValue();
        }
        public void Transform(Matrix m)
        {
            transform *= m;
        }
        private void InitValue()
        {
            this.SpriteBatch = new SpriteBatch(DSEngine.Instance.GameInstance.GraphicsDevice);
            
            this.Alpha = 1.0f;
            this.Color = Color.White;
            this.Scale = new Vector2(1f, 1f);
            this.Rotation = 0;

            this.Visible = true;
            this.Freeze = false;
            this.Enable = true;

            this.Position = new Vector2(0, 0);

            this._width = DSEngine.Instance.BufferWidth;
            this._height = DSEngine.Instance.BufferHeight;

            this.SpriteBatch = new SpriteBatch(DSEngine.Instance.GameInstance.GraphicsDevice);
            this.SpriteSortMode = Microsoft.Xna.Framework.Graphics.SpriteSortMode.Deferred;
            this.BlendState = BlendState.AlphaBlend;
            this.SamplerState = SamplerState.LinearClamp;
            this.DepthStencilState = DepthStencilState.None;
            this.RasterizerState = RasterizerState.CullCounterClockwise;

            this.transform = Matrix.CreateTranslation(new Vector3());

            this.Center = new Vector2();
        }
        public Layout()
        {
            InitValue();
        }
        public SpObject GetObjectByTag(object tag)
        {
            foreach (var item in objs)
            {
                if (item.Tag == tag)
                    return item;
            }
            return null;
        }
        public void AddObject(SpObject obj)
        {
            objs.Add(obj);
        }
        
        public void RemoveObject(SpObject obj)
        {
            obj2remove.Add(obj);
           
        }
        public override void Dispose()
        {
            foreach (var item in this.objs)
            {
                item.Dispose();
            }
        }
        internal bool SystemHandleInput(GameTime gameTime, InputState input)
        {
            if (input.TouchLocation.Count == 0)
                return false;
            bool inputHandled = false;
            var sort = from k in objs orderby k.ZOrder descending select k;
            List<TouchLocation> locs = new List<TouchLocation>();
            locs = input.TouchLocation;
            List<TouchLocation> l2r = new List<TouchLocation>();
            foreach (var item in sort)
            {
                if (item.Visible == false)
                    continue;
                foreach (var state in locs)
                { 
                    if(item.CheckTouch(state))
                    {
                        InputData data = new InputData();
                        data.Location = state;
                        data.Handled = false;
                        inputHandled = item.SystemHandleInput(gameTime, data);
                        if (data.Handled)
                        {
                            l2r.Add(state);
                        }
                    }
                }
                foreach (var t in l2r)
                {
                    locs.Remove(t);
                    input.TouchLocation.Remove(t);
                }
                l2r.Clear();
            }
            l2r.Clear();
            foreach (var item in locs)
            {
                if (CheckTouch(item))
                {
                    InputData data = new InputData();
                    data.Location = item;
                    data.Handled = false;
                    SystemHandleInput(gameTime, data);
                    if (data.Handled)
                    {
                        l2r.Add(data.Location);
                    }
                }
            }
            foreach (var t in l2r)
            {
                locs.Remove(t);
                input.TouchLocation.Remove(t);
            }
            return false; 
        }
        protected override List<BoundingBox> UpdateBoundingBox(GameTime gameTime)
        {
            List<BoundingBox> bl = new List<BoundingBox>();
            BoundingBox bb=  new BoundingBox ();
            bb.Min = new Vector3 (this.Position,0);
            bb.Max = new Vector3(this.Position + new Vector2(this.Width, this.Height), 0);
            bl.Add(bb);
            return bl;
        }

        public Vector2 Center { get; set; }

        internal bool SystemHandleBackKey(GameTime gameTime)
        {
            return HandleBackKey(gameTime);
        }

        protected virtual bool HandleBackKey(GameTime gameTime)
        {
            return false;
        }
        new public void Update(Microsoft.Xna.Framework.GameTime gameTime)
        {
            if (!Freeze && Enable)
            {
                boundingBox = UpdateBoundingBox(gameTime);
                InnerUpdate(gameTime);
                
                foreach (var obj in obj2remove)
	            {
                    obj.IsDisposed = true;
                    objs.Remove(obj);
	            }
                obj2remove.Clear();

                var sort = from k in objs orderby k.ZOrder select k;
                foreach (var item in sort)
                {
                    if(item.Enable)
                        item.Update(gameTime);
                }
            }
            //if (Enable)
            //{
            //    boundingBox = UpdateBoundingBox(gameTime);
            //    InnerUpdate(gameTime);
            //}
        }
        Matrix CreateTranformMatrix()
        {
            Matrix m = Matrix.Identity;
            m *= Matrix.CreateTranslation(new Vector3(-this.Center, 0));
            m *= Matrix.CreateRotationZ(MathHelper.ToRadians(this.Rotation));
            m *= Matrix.CreateScale(this.Scale.X, this.Scale.Y, 0);

            m *= Matrix.CreateTranslation(new Vector3(this.Position + this.Center, 0));
            return m;
        }
        new public void Draw(Microsoft.Xna.Framework.GameTime gameTime)
        {
            if (Visible & Enable)
            {
                Matrix m = CreateTranformMatrix();
                var sort = from k in objs orderby k.ZOrder select k;
                //this.SpriteBatch.Begin();
                this.SpriteBatch.Begin(
                    this.SpriteSortMode,
                    this.BlendState,
                    this.SamplerState,
                    this.DepthStencilState,
                    this.RasterizerState,
                    null,
                    m);
                foreach (var item in sort)
                {
                    if(item.Visible)
                        item.Draw(gameTime);
                }
                InnerDraw(gameTime);
                this.SpriteBatch.End();
            }  
        } 

        protected override void InnerDraw(GameTime gt)
        {
            //base class do nothing
            //waiting for override 
        }
        protected override void InnerUpdate(GameTime gt)
        {
            //base class do nothing
            //waiting for override 
        }
    }
}
